using System;
using System.Collections;
using System.IO;
using System.Xml.Serialization;

/// <summary>
/// Summary description for SchedulerSettings
/// </summary>
public class Settings
{
	/// <summary>
	/// The level of logging that should be done.
	/// </summary>
	public LogLevelType LogLevel;
	/// <summary>
	/// The full filepath to where the log should be written.
	/// </summary>
	public string LogFilepath;
	/// <summary>
	/// Whether the processing of records should be paused or not.  This can only take effect after the
	/// current processing run has finished.
	/// </summary>
	public bool Pause;
	/// <summary>
	/// When the settings file was last modified.
	/// </summary>
	[XmlIgnore]
	public DateTime LastModified;
	/// <summary>
	/// An collection of <see cref="Settings.RecurringEvent"/>.
	/// </summary>
	[XmlArray("RecurringEvents")]
	[XmlArrayItem("Event", Type = typeof(Settings.RecurringEvent))]
	public ArrayList RecurringEvents;
	/// <summary>
	/// A collection of <see cref="Settings.OneTimeEvent"/>.
	/// </summary>
	[XmlArray("OneTimeEvents")]
	[XmlArrayItem("Event", Type = typeof(Settings.OneTimeEvent))]
	public ArrayList OneTimeEvents;

	/// <summary>
	/// Initializes a new instance of the <see cref="Settings"/> class.
	/// </summary>
	public Settings()
	{
		LogLevel = LogLevelType.Normal;
		Pause = false;
		LastModified = new DateTime();
		RecurringEvents = new ArrayList();
		OneTimeEvents = new ArrayList();
	}

	/// <summary>
	/// Determines whether the settings contained in memory should be updated based on the filepath.
	/// </summary>
	/// <param name="filepath">The filepath.</param>
	/// <returns>
	/// 	<c>true</c> if the update is needed; otherwise, <c>false</c>.
	/// </returns>
	public bool IsUpdateNeeded(string filepath)
	{
		FileInfo fi = new FileInfo(filepath);
		if (LastModified < fi.LastWriteTime)
			return true;
		return false;
	}

	#region Serialization

	/// <summary>
	/// Saves the settings to the specified filepath.
	/// </summary>
	/// <param name="filepath">The filepath.</param>
	public void Save(string filepath)
	{
		XmlSerializer s = new XmlSerializer(typeof(Settings));
		TextWriter w = new StreamWriter(filepath);
		s.Serialize(w, this);
		w.Close();
	}

	/// <summary>
	/// Loads the settings from the specified filepath.
	/// </summary>
	/// <param name="filepath">The filepath.</param>
	/// <returns></returns>
	public static Settings Load(string filepath)
	{
		Settings settings = new Settings();
		FileInfo fi;

		if (filepath == null)
			throw new ArgumentNullException("filepath", "The argument filepath cannot be null.");

		if (File.Exists(filepath))
		{
			XmlSerializer s = new XmlSerializer(typeof(Settings));
			TextReader r = new StreamReader(filepath);
			settings = (Settings)s.Deserialize(r);
			r.Close();
		}
		else
			throw new FileNotFoundException("The file could not be found", filepath);

		fi = new FileInfo(filepath);
		settings.LastModified = fi.LastWriteTime;

		return settings;
	}

	#endregion

	#region Enums/Classes

	/// <summary>
	/// The level of logging.
	/// </summary>
	public enum LogLevelType
	{
		/// <summary>
		/// Lots of logging.
		/// </summary>
		Debug = 0,
		/// <summary>
		/// A little logging.
		/// </summary>
		Normal,
		/// <summary>
		/// No logging at all.
		/// </summary>
		None
	}

	/// <summary>
	/// A unit of time.
	/// </summary>
	public enum RepeatUnitType
	{
		/// <summary>
		/// Represents a minute.
		/// </summary>
		Minutes = 0,
		/// <summary>
		/// Represents a hour.
		/// </summary>
		Hours,
		/// <summary>
		/// Represents a day.
		/// </summary>
		Days,
		/// <summary>
		/// Represents a month.
		/// </summary>
		Months
	}

	/// <summary>
	/// Base class for an event
	/// </summary>
	public class Event
	{
		/// <summary>
		/// The name of the Event.
		/// </summary>
		public string Name;
		/// <summary>
		/// The path to the directory where the settings files (browsers.xml, etc.) are stored.
		/// </summary>
		public string SettingsDirectory;
		/// <summary>
		/// The path to the profile used to generate this report.
		/// </summary>
		public string ProfilePath;
		/// <summary>
		/// The filepaths of the logs that are to be processed.
		/// </summary>
		public LogToProcess[] LogsToProcess;
		/// <summary>
		/// The earliest possible date/time combination that this event can be fired.
		/// </summary>
		public DateTime Start;

		/// <summary>
		/// Initializes a new instance of the <see cref="Event"/> class.
		/// </summary>
		public Event()
		{
			Start = new DateTime();
		}
	}

	/// <summary>
	/// An event that happens over and over on a set schedule.
	/// </summary>
	public class RecurringEvent : Event
	{
		/// <summary>
		/// The absolute last second that this event can run.
		/// </summary>
		public DateTime Stop;
		/// <summary>
		/// When this event should next be fired.
		/// </summary>
		public DateTime NextRun;
		/// <summary>
		/// The unit part of how often this event should fire.  Paired with RepeatValue
		/// </summary>
		public RepeatUnitType RepeatUnit;
		/// <summary>
		/// The quantity part of how often this event should fire.  Paired with: <see cref="RepeatUnitType"/> RepeatUnit.
		/// </summary>
		public int RepeatValue;
		/// <summary>
		/// The directory where the output reports should be saved.
		/// </summary>
		public string SaveDirectory;
		/// <summary>
		/// If true then data duplication in reports should be permitted.
		/// </summary>
		public bool Reprocessing;
		/// <summary>
		/// Log files which have already been processed.  We track these so that we do not duplicate 
		/// data in the reports.
		/// </summary>
		public string[] ProcessedLogs;

		/// <summary>
		/// Initializes a new instance of the <see cref="RecurringEvent"/> class.
		/// </summary>
		public RecurringEvent()
			: base()
		{
			Stop = new DateTime();
			NextRun = new DateTime();
			RepeatUnit = RepeatUnitType.Minutes;
		}
	}

	/// <summary>
	/// An event that happens only one time.
	/// </summary>
	public class OneTimeEvent : Event
	{
		/// <summary>
		/// The filepath where the output report should be saved.
		/// </summary>
		public string SaveFilepath;

		/// <summary>
		/// Initializes a new instance of the <see cref="OneTimeEvent"/> class.
		/// </summary>
		public OneTimeEvent()
			: base()
		{
		}
	}

	/// <summary>
	/// Represents a log(s) to process.  This is done by going to the Directory and running a RegEx 
	/// match on all filenames in that directory with SearchString.
	/// </summary>
	public class LogToProcess
	{
		/// <summary>
		/// The directory that should be searched using the SearchString.
		/// </summary>
		public string Directory;
		/// <summary>
		/// The RegEx string on which matches should be based.
		/// </summary>
		public string SearchString;

		/// <summary>
		/// Initializes a new instance of the <see cref="LogToProcess"/> class.
		/// </summary>
		public LogToProcess()
		{
		}
	}

	#endregion
}